%{
/*********************************************
YACC file
基础程序
Date:2023/9/19
forked SherryXiye
**********************************************/
#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>
#include<string.h>

struct symtable
{
  char*name;
  double val;
}st[10];// 符号表
struct symtable *symsearch(char*s); 
int yylex();
extern int yyparse();
FILE* yyin;
void yyerror(const char* s);
%}
%union{
 double dig;
 struct symtable *var;
}
//注意先后定义的优先级区别
%token '+' '-'
%token <dig>NUMBER
%token '*' '/'
%token '(' ')'
%token <var>IDENT
%token '='

%right '='
%left '+' '-'
%left '*' '/'
%left '(' ')' 
%right UMINUS         

%type <dig> expr

%%


lines   :       lines expr ';' { printf("%f\n", $2); }
        |       lines ';'
        |
        ;

expr    :       expr '+' expr   { $$=$1+$3; }
        |       expr '-' expr   { $$=$1-$3; }
        |       expr '*' expr   { $$=$1*$3; }
        |       expr '/' expr   { $$=$1/$3; }
        |       '('expr')'      { $$=$2;}
        |       '-' expr %prec UMINUS   {$$=-$2;}
        |       NUMBER		{$$=$1;}	
        |       IDENT '=' expr	{$1->val=$3;$$=$3;}
        |       IDENT           {$$=$1->val;}							
        ;
%%

// programs section

int yylex()
{
    int t;
    while(1){
        t=getchar();
        if(t==' '||t=='\t'||t=='\n'||t=='\r'){
         ;//do noting
        }else if(isdigit(t)){
            //TODO:解析多位数字返回数字类型 
            /*yacc内部定义的变量yylval用于传递属性值*/
            yylval.dig = 0;
            while(isdigit(t)) {
               yylval.dig = yylval.dig * 10 + t -'0';
               t = getchar();
            }
            ungetc(t , stdin);
            return NUMBER;
        }else if(t=='+'){
            return '+';
        }else if(t=='-'){
            return '-';
        }//TODO:识别其他符号
        else if(t=='*'){
            return '*';
        }else if(t=='/'){
            return '/';
        }else if(t=='('){
            return '(';
        }else if(t==')'){
            return ')';
        }
        else if((t >= 'a' && t <= 'z' ) || ( t >= 'A' && t<= 'Z' ) || ( t == '_' ))
        {
            int i=0;
            char tmp[50];
            while((t >= 'a' && t <= 'z' ) || ( t >= 'A' && t<= 'Z' ) || ( t == '_' )||(t>='0'&&t<='9'))
            {
            	tmp[i]=t;
            	t=getchar();
            	i++;
            }
            tmp[i]='\0';
            yylval.var=symsearch(tmp);
            ungetc(t , stdin);
            return IDENT;
        }
        else if(t=='=')
        {return '=';}
        else{
            return t;
        }
    }
}

int main(void)
{
    yyin=stdin;
    do{
        yyparse();
    }while(!feof(yyin));
    return 0;
}
void yyerror(const char* s){
    fprintf(stderr,"Parse error: %s\n",s);
    exit(1);
}
struct symtable *symsearch(char*s)
{
   char* p;
   struct symtable *sp;
   for(sp=st;sp<&st[10];sp++)
   {
   	if(sp->name && !strcmp(sp->name,s))//找到
   	{return sp;}
   	
   	if(!sp->name)//找不到，创建
   	{
   	   sp->name=strdup(s);
   	   return sp;
   	}
   }
   yyerror("error");
   exit(1);

}
